home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / lang_c / cserial / 8250dtr.c < prev    next >
C/C++ Source or Header  |  1990-04-04  |  12KB  |  456 lines

  1. /*
  2.  *                                DTR8250.C
  3.  *
  4.  *                    NSC8250 DTR Handshake ISR Module
  5.  *
  6.  *                           Written for the
  7.  *
  8.  *                              Datalight
  9.  *                           Microsoft V 5.x
  10.  *                                TurboC
  11.  *                                  &
  12.  *                               Zortech
  13.  *
  14.  *                             C Compilers
  15.  *
  16.  *            Copyright (c) John Birchfield 1987, 1988, 1989
  17.  */
  18.  
  19. #include <stdio.h>
  20. #include "dependnt.h"
  21. #include "queue.h"
  22. #include "8250nsc.h"
  23. #include "8250dtr.h"
  24. #include "timer.h"
  25.  
  26. #if (!defined (TRUE))
  27. #    define TRUE  (1)
  28. #    define FALSE (0)
  29. #endif
  30.  
  31. unsigned DTR_PORT_channel;      /* Either 1 or 2 for COM1 or COM2       */
  32. char    dtr8250_SAVE_int_mask,  /* saved interrupt controller mask word */
  33.         dtr8250_IER_save = 0,   /* Saved off Interrupt Enable Register  */
  34.         dtr8250_LCR_save = 0,   /* Saved off Line Control Register      */
  35.         dtr8250_MCR_save = 0,   /* Saved off Modem Control Register     */
  36.         dtr8250_DL_lsb = 0,     /* Saved off Baud Rate LSB              */
  37.         dtr8250_DL_msb = 0;     /* Saved off Baud Rate MSB              */
  38.  
  39.  
  40.  
  41. volatile unsigned DTR_PORT_addr;
  42. volatile char DTR_PORT_status, RCV_disabled = FALSE, XMIT_disabled = TRUE, dtr8250_MSR_reg = 0;
  43. volatile QUEUE *dtr8250_inqueue;
  44. #if (defined (DLC))
  45. extern void outp ();
  46. #endif
  47.  
  48.  
  49. #define DISABLE_xmit outbyte (DTR_PORT_addr+IER, RX_enable)
  50. #define ENABLE_xmit  outbyte (DTR_PORT_addr+IER, RX_TX_enable)
  51. #define DROPPED_cts  ((dtr8250_MSR_reg&0x10)==0)
  52. #define DROPPED_dsr  ((dtr8250_MSR_reg&0x20)==0)
  53. #define DROPPED_dtr  ((dtr8250_MSR_reg&0x30)!=0x30)
  54. #define ASSERT_dtr   outbyte (inbyte (DTR_PORT_addr+MCR)|9, DTR_PORT_addr+MCR)
  55. #define DROP_dtr     outbyte (inbyte (DTR_PORT_addr+MCR)&0x0A, DTR_PORT_addr+MCR)
  56. #define ASSERT_rts   outbyte (inbyte (DTR_PORT_addr+MCR)|0x0A, DTR_PORT_addr+MCR)
  57. #define DROP_rts     outbyte (inbyte (DTR_PORT_addr+MCR)&9, DTR_PORT_addr+MCR)
  58. #define TSRE_bit     0x40
  59.  
  60.  
  61.  
  62. /*
  63.  *    DTR8250_ISR - This Interrupt Service Routine attached to either COM1
  64.  *                  or COM2.  It drives the NSC8250 with Hardware
  65.  *                  Handshaking.  i.e. Flow of Control is maintained by 
  66.  *                  RTS (Request to Send) CTS (Clear to Send) Logic.
  67.  *                After installation by Catch_Rt, it catches the
  68.  *                8250 interrupts and en_queues incoming characters
  69.  *                from the Serial Port - and de-queues outgoing
  70.  *                characters to the Serial Port.
  71.  */
  72.  
  73. #if (!defined (DLC))
  74. void    (interrupt far * dtr_save_vec) (void);
  75. void interrupt far 
  76. dtr8250_isr (void)
  77. #else
  78. int 
  79. dtr8250_isr ()
  80. #endif
  81. {
  82.     int     ch;
  83.     char    test_status;
  84.  
  85.     enable ();
  86.     test_status = inbyte ((DTR_PORT_addr + IIR));
  87.     do
  88.     {
  89.         switch (test_status)
  90.         {
  91.  
  92.             case IIR_rls:
  93.                 DTR_PORT_status |= inbyte ((DTR_PORT_addr + LSR));
  94.                 break;
  95.  
  96.             case IIR_receive:
  97.                 ch = inbyte (DTR_PORT_addr);
  98.                 if ((en_queue (dtr8250_inqueue, ch) < 10) && !RCV_disabled)
  99.                 {
  100.                     RCV_disabled = TRUE;
  101.                     DROP_dtr;
  102.                 }
  103.                 else
  104.                 if (RCV_disabled && (queue_avail (dtr8250_inqueue) > 20))
  105.                 {
  106.                     RCV_disabled = FALSE;
  107.                     ASSERT_dtr;
  108.                 }
  109.                 break;
  110.  
  111.             case IIR_transmit:
  112.                 DISABLE_xmit;
  113.                 break;
  114.  
  115.             case IIR_mstatus:
  116.                 dtr8250_MSR_reg = inbyte (DTR_PORT_addr + MSR);
  117.                 if (RCV_disabled && (queue_avail (dtr8250_inqueue) > 20))
  118.                 {
  119.                     RCV_disabled = FALSE;
  120.                     ASSERT_dtr;
  121.                 }
  122.                 break;
  123.         }
  124.     } while ((test_status = inbyte (DTR_PORT_addr + IIR)) != IIR_complete);
  125.     disable ();
  126.     outbyte (INT_cntrl, EOI_word);
  127. #if (defined (DLC))
  128.     return (1);
  129. #endif
  130. }
  131.  
  132.  
  133.  
  134.  
  135. /*
  136.  *    DTR8250_INIT - Here we get the address of the 8250 Port
  137.  *                   which corresponds to the channel passed in.
  138.  *                   We then massage the 8259 Interrupt Controller
  139.  *                   calculate the Physical Interrupt and save off
  140.  *                   the 8250's current contents.  Then attach the
  141.  *                   nsc8250_interrupt routine to the interrupt and
  142.  *                   return the rt returned index for saving - it's
  143.  *                   needed to terminate the interrupt.
  144.  */
  145.  
  146. #define DTR8250_STACK_SIZE 1024
  147. int        dtr8250_intno;
  148. static int dtr_intmask [] = { 0xef, 0xf7, 0xef, 0xf7 };
  149. /*
  150.  * The above 8259 mask bits are determined from the formula
  151.  *          mask = ~(1 << (5 - PORT_CHANNEL));
  152.  * The array assumes that COM3 and COM4 use the same interrupts
  153.  * as COM1 and COM2.
  154.  */
  155. static int dtr_intno   [] = { 12, 11, 12, 11 };
  156. /*
  157.  * The above interrupt number array is based on the algorithm
  158.  *       dtr8250_intno = (13 - PORT_channel);
  159.  */
  160.  
  161.  
  162. void 
  163. dtr8250_init (channel, buf_size)
  164. int     channel, buf_size;
  165. {
  166.     int     Dos_address, mask;
  167.     DTR_PORT_channel = channel;
  168.     dtr8250_inqueue = alloc_queue (buf_size);
  169.     Dos_address = (DTR_PORT_channel - 1) * 2;
  170.     peekmem (0x40, Dos_address, DTR_PORT_addr);
  171.     mask = dtr_intmask [DTR_PORT_channel-1];
  172.     dtr8250_SAVE_int_mask = inbyte (INT_mask);
  173.     mask &= dtr8250_SAVE_int_mask;
  174.     dtr8250_intno = dtr_intno [DTR_PORT_channel-1];
  175.     dtr8250_LCR_save = inbyte (DTR_PORT_addr + LCR);
  176.     disable ();
  177.     outbyte (DTR_PORT_addr + LCR, dtr8250_LCR_save | LCR_DLAB);
  178.     dtr8250_MCR_save = inbyte (DTR_PORT_addr + MCR);
  179.     dtr8250_DL_lsb = inbyte (DTR_PORT_addr);
  180.     dtr8250_DL_msb = inbyte (DTR_PORT_addr + 1);
  181.     outbyte (DTR_PORT_addr + LCR, dtr8250_LCR_save & 0x7F);
  182.     dtr8250_IER_save = inbyte (DTR_PORT_addr + IER);
  183.     enable ();
  184. #if (defined (DLC))
  185.     int_intercept (dtr8250_intno, &dtr8250_isr, DTR8250_STACK_SIZE);
  186. #else
  187.     dtr_save_vec = getvect (dtr8250_intno);
  188.     setvect (dtr8250_intno, dtr8250_isr);
  189. #endif
  190.     DELAY_init ();
  191.     outbyte (INT_mask, mask);
  192. }
  193.  
  194.  
  195.  
  196.  
  197. /*
  198.  *    DTR8250_TERM - This routine restores the RS232 Vector back to its
  199.  *                   state before DTR8250_INIT was called.
  200.  */
  201.  
  202. void 
  203. dtr8250_term (int restore)
  204. {
  205.     disable ();
  206.     outbyte (INT_mask, dtr8250_SAVE_int_mask);
  207.     if (restore)
  208.     {
  209.         outbyte (DTR_PORT_addr + LCR, LCR_DLAB);
  210.         outbyte (DTR_PORT_addr, dtr8250_DL_lsb);
  211.         outbyte (DTR_PORT_addr + 1, dtr8250_DL_msb);
  212.         outbyte (DTR_PORT_addr + MCR, dtr8250_MCR_save);
  213.         outbyte (DTR_PORT_addr + LCR, 0x7F);
  214.         outbyte (DTR_PORT_addr + IER, dtr8250_IER_save);
  215.         outbyte (DTR_PORT_addr + LCR, dtr8250_LCR_save);
  216.     }
  217. #if (defined (DLC))
  218.     int_restore (dtr8250_intno);
  219. #else
  220.     setvect (dtr8250_intno, dtr_save_vec);
  221. #endif
  222. }
  223.  
  224.  
  225.  
  226.  
  227. /*
  228.  *    DTR8250_READ - this routine looks in the RS232hw_inqueue for a character
  229.  *
  230.  */
  231.  
  232. int 
  233. dtr8250_read (void)
  234. {
  235.     int     ch;
  236.     disable ();
  237.     ch = de_queue (dtr8250_inqueue);
  238.     enable ();
  239.     return (ch);
  240. }
  241.  
  242.  
  243.  
  244.  
  245. /*
  246.  *    DTR8250_TIMED_READ - attempts to read rs232 port - if no char
  247.  *                         available in number of seconds passed
  248.  *                         returns -1
  249.  */
  250.  
  251. int 
  252. dtr8250_timed_read (int sec)
  253. {
  254.     int     ch;
  255.  
  256.     timer_set ();
  257.     while ((ch = dtr8250_read ()) == -1)
  258.         if ((timer_read () / 18) > sec)
  259.             break;
  260.     return (ch);
  261. }
  262.  
  263.  
  264.  
  265.  
  266. /*
  267.  *    DTR8250_WRITE - plain vanilla write to the port - check to see that
  268.  *                    the chip may need a kick in the pants before returning
  269.  */
  270.  
  271. int 
  272. dtr8250_write (char ch)
  273. {
  274.     while ((inbyte (DTR_PORT_addr + LSR) & TSRE_bit) == 0)
  275.         ;
  276.     dtr8250_MSR_reg = inbyte ((DTR_PORT_addr + MSR));
  277.     if (DROPPED_dtr)
  278.         return -1;
  279.     outbyte (DTR_PORT_addr, ch);
  280.     if (RCV_disabled && (queue_avail (dtr8250_inqueue) > 20))
  281.     {
  282.         RCV_disabled = FALSE;
  283.         ASSERT_dtr;
  284.     }
  285. }
  286.  
  287.  
  288.  
  289.  
  290. /*
  291.  *    DTR8250_DTRNR - drop Data Terminal Ready Line
  292.  */
  293. void
  294. dtr8250_dtnr (void)
  295. {
  296.     char mcr_save;
  297.     disable ();
  298.     mcr_save = inbyte (DTR_PORT_addr + MCR);
  299.     outbyte (DTR_PORT_addr + MCR, 0);
  300.     DELAY_loop (500);
  301.     outbyte (DTR_PORT_addr + MCR, mcr_save);
  302.     enable ();
  303. }
  304.  
  305.  
  306.  
  307.  
  308. /*
  309.  *    DTR8250_GET_STATUS - returns the current NSC8250 status and
  310.  *                         resets any error condition.
  311.  */
  312.  
  313. int 
  314. dtr8250_get_status (void)
  315. {
  316.     char    rval = DTR_PORT_status;
  317.     DTR_PORT_status &= ERROR_reset;
  318.     return ((int) rval);
  319. }
  320.  
  321.  
  322.  
  323.  
  324.  
  325. /*
  326.  *    DTR8250_MODEM_STATUS - returns the current NSC8250 Modm Status Register
  327.  *                           contents.
  328.  */
  329.  
  330. int 
  331. dtr8250_modem_status (void)
  332. {
  333.     dtr8250_MSR_reg = inbyte (DTR_PORT_addr + MSR);
  334.     return ((int) dtr8250_MSR_reg);
  335. }
  336.  
  337.  
  338.  
  339.  
  340.  
  341. /*
  342.  *    DTR8250_WRITE_BREAK - Write a BREAK Character
  343.  */
  344.  
  345. void 
  346. dtr8250_write_break (void)
  347. {
  348.     int     i;
  349.     disable ();
  350.     while ((inbyte (DTR_PORT_addr + LSR) & 0x40) == 0)
  351.         ;
  352.     outbyte (DTR_PORT_addr + LCR, inbyte (DTR_PORT_addr + LCR) | 0x40);
  353.     for (i = 0; i < 13000; i++)
  354.         ;
  355.     outbyte (DTR_PORT_addr + LCR, inbyte (DTR_PORT_addr + LCR) & 0xBF);
  356.     enable ();
  357. }
  358.  
  359.  
  360.  
  361.  
  362.  
  363. /*
  364.  *    DTR8250_PORT_INIT (Cmd) configures the 8250
  365.  *        cmd is a string of the form baud parity stop data i.e 
  366.  *        300 n 1 8
  367.  *
  368.  *        baud - 300, 600, 1200, 2400, 4800, 9600
  369.  *        parity - n -> no parity check
  370.  *                 o -> odd parity
  371.  *                 e -> even parity
  372.  *        stop   - 1 -> 1 stop bit
  373.  *                 2 -> 2 stop bits
  374.  *        data   - 5, 6, 7, 8 data bits
  375.  */
  376.  
  377. void 
  378. dtr8250_port_init (cmd)
  379. char   *cmd;
  380. {
  381.     unsigned baud, data, mode_word, parity, stop, xoff;
  382.     char    pty[2];
  383.     sscanf (cmd, "%d %1s %d %d", &baud, pty, &stop, &data);
  384.     *pty = toupper (*pty);
  385.     switch (*pty)
  386.     {
  387.         case 'E':
  388.             parity = 3;
  389.             break;
  390.         case 'O':
  391.             parity = 1;
  392.             break;
  393.         case 'N':
  394.             parity = 0;
  395.             break;
  396.         default:
  397.             parity = 0;
  398.             break;
  399.     }
  400.     stop = (--stop & 1);
  401.     stop <<= 2;
  402.     baud /= 10;
  403.     baud = 11520 / baud;
  404.     parity <<= 3;
  405.     parity &= 0x018;
  406.     data -= 5;
  407.     data &= 3;
  408.     mode_word = data | stop | parity;
  409.     disable ();
  410.     outbyte (DTR_PORT_addr + LCR, inbyte (DTR_PORT_addr + LCR) | LCR_DLAB);
  411.     outbyte (DTR_PORT_addr, baud % 256);
  412.     outbyte (DTR_PORT_addr + 1, baud / 256);
  413.     outbyte (DTR_PORT_addr + LCR, mode_word & 0x7F);
  414.     outbyte (DTR_PORT_addr + IER, RX_enable);
  415.     outbyte (DTR_PORT_addr + MCR, 0x0B);
  416.  
  417.     inbyte (DTR_PORT_addr + LSR);
  418.     dtr8250_MSR_reg = inbyte ((DTR_PORT_addr + MSR));
  419.     inbyte (DTR_PORT_addr);
  420.     enable ();
  421. }
  422.  
  423.  
  424.  
  425.  
  426. /*---------------------- dtr8250_port_enable () ----------------------*/
  427. /*
  428.  *
  429.  */
  430. void
  431. dtr8250_port_enable (void)
  432. {
  433.     disable ();
  434.     outbyte (DTR_PORT_addr + IER, RX_enable);
  435.     outbyte (DTR_PORT_addr + MCR, 0x0B);
  436.  
  437.     inbyte (DTR_PORT_addr + LSR);
  438.     dtr8250_MSR_reg = inbyte ((DTR_PORT_addr + MSR));
  439.     inbyte (DTR_PORT_addr);
  440.     enable ();
  441. }
  442.  
  443.  
  444.  
  445.  
  446. /*------------------------ dtr8250_lines () ------------------------*/
  447. /*
  448.  *
  449.  */
  450. void
  451. dtr8250_lines (void)
  452. {
  453.     printf ("8250 DTR_PORT_addr = %04x\n", DTR_PORT_addr);
  454.     printf ("8250 MSR = %02x\n", inbyte (DTR_PORT_addr + MSR));
  455. }
  456.